home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / hat-n-coat / mcqueer-lib < prev    next >
Encoding:
Internet Message Format  |  1989-03-23  |  26.7 KB

  1. Subject:  v18i054:  Library for hat/coat and others
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Bob McQueer <mtxinu!rtech!weevil!bobm@uunet.uu.net>
  7. Posting-number: Volume 18, Issue 54
  8. Archive-name: mcqueer-lib
  9.  
  10. [  I don't want to get into the practice of posting everyone's favorite
  11.    toolkit/library...  --r$  ]
  12.  
  13. This is a small set of utilities for generic use, at least in bobm
  14. generated programs.
  15.  
  16. ----------
  17. #! /bin/sh
  18. # This is a shell archive, meaning:
  19. # 1. Remove everything above the #! /bin/sh line.
  20. # 2. Save the resulting text in a file.
  21. # 3. Execute the file with /bin/sh (not csh) to create:
  22. #    README
  23. #    Makefile
  24. #    diagnostic.c
  25. #    hash.c
  26. #    prime.c
  27. #    strstore.c
  28. #    strtok.c
  29. export PATH; PATH=/bin:/usr/bin:$PATH
  30. echo shar: "extracting 'README'" '(637 characters)'
  31. if test -f 'README'
  32. then
  33.     echo shar: "will not over-write existing file 'README'"
  34. else
  35. cat << \SHAR_EOF > 'README'
  36. This is a small set of utilities for generic use, at least in bobm
  37. generated programs:
  38.  
  39.     hash.c, prime.c - manage hash tables.
  40.     strstore.c - store and free copies of strings.
  41.     diagnostic.c - produce diagnostic & fatal error messages.
  42.  
  43. read comments in the individual sources for directions on using them.
  44.  
  45. strtok.c is also contained herein.  If you are SYSV, or any other system
  46. which has that in the runtime library, remove it from the makefile.
  47.  
  48. Before you build, fill in the makefile to put the results where you want them.
  49.  
  50. hash.c and str_store.c manage dynamic memory.  #define's in those files
  51. control allocation block sizes, etc.
  52. SHAR_EOF
  53. fi
  54. echo shar: "extracting 'Makefile'" '(810 characters)'
  55. if test -f 'Makefile'
  56. then
  57.     echo shar: "will not over-write existing file 'Makefile'"
  58. else
  59. cat << \SHAR_EOF > 'Makefile'
  60. #
  61. # where to put the library
  62. #
  63. LIBARC = $(HOME)/lib/bobm.a
  64.  
  65. # if your compiler doesn't like the initialization of a pointer with
  66. # an array address in strstore.c, define NO_PTR_INIT
  67. #
  68. # if you define HASHMAGIC to be some number, you will get magic number
  69. # checks in the hash table routines, which can be helpful in tracking
  70. # down instances of client code passing bad context addresses.  Not done
  71. # by default to avoid overhead.  See hash.c
  72. #
  73. CFLAGS = -O
  74.  
  75. #
  76. # if strtok() is available in your c runtime library, remove it from
  77. # the list - this will be all SYSV, and some BSD systems like ULTRIX
  78. #
  79. LIBOBJS = hash.o diagnostic.o prime.o strstore.o strtok.o
  80.  
  81. #
  82. # for SYSV, make RANLIB an effective no-op, like "ls" or "echo"
  83. #
  84. RANLIB = ranlib
  85.  
  86. lib : $(LIBOBJS)
  87.     ar rvu $(LIBARC) $(LIBOBJS)
  88.     $(RANLIB) $(LIBARC)
  89. SHAR_EOF
  90. fi
  91. echo shar: "extracting 'diagnostic.c'" '(1977 characters)'
  92. if test -f 'diagnostic.c'
  93. then
  94.     echo shar: "will not over-write existing file 'diagnostic.c'"
  95. else
  96. cat << \SHAR_EOF > 'diagnostic.c'
  97. #include <stdio.h>
  98.  
  99. /*
  100. ** generic error message routines.  Diag_xxx, may be externally set by caller.
  101. **
  102. ** possible portability problem - use of several "long" arguments to pass
  103. ** stack through to underlying printf() family routine.
  104. */
  105.  
  106. /*
  107. **
  108. **    Copyright (c) 1987, Robert L. McQueer
  109. **        All Rights Reserved
  110. **
  111. ** Permission granted for use, modification and redistribution of this
  112. ** software provided that no use is made for commercial gain without the
  113. ** written consent of the author, that all copyright notices remain intact,
  114. ** and that all changes are clearly documented.  No warranty of any kind
  115. ** concerning any use which may be made of this software is offered or implied.
  116. **
  117. */
  118.  
  119. char *Diag_file = "";        /* filename for use in diagnostic message */
  120. int Diag_line = 1;        /* diagnostic line number */
  121. int Diag_count = 0;        /* diagnostic counter */
  122. FILE *Diag_fp = stderr;        /* output stream for messages */
  123. char *Diag_cmd = "?";        /* command name for fatal() / usage() */
  124.  
  125. static int (*Fatcall)() = NULL;
  126.  
  127. /*
  128. ** print nonfatal diagnostic with line number from an input file.  Format
  129. ** compatible with "context"
  130. */
  131. diagnostic(s,a,b,c,d,e,f)
  132. char *s;
  133. long a,b,c,d,e,f;
  134. {
  135.     fprintf(Diag_fp,"%s line %d: ",Diag_file,Diag_line);
  136.     fprintf(Diag_fp,s,a,b,c,d,e,f);
  137.     fprintf(Diag_fp,"\n");
  138.     ++Diag_count;
  139. }
  140.  
  141. /*
  142. ** print fatal error message and exit.  May call user set cleanup routine first.
  143. ** argument list passed to fatal() will also be passed to cleanup routine.
  144. */
  145. fatal (s,a,b,c,d,e,f)
  146. char *s;
  147. long a,b,c,d,e,f;
  148. {
  149.     fprintf (Diag_fp,"%s: ",Diag_cmd);
  150.     fprintf (Diag_fp,s,a,b,c,d,e,f);
  151.     fprintf (Diag_fp,"\n");
  152.     if (Fatcall != NULL)
  153.         (*Fatcall) (s,a,b,c,d,e,f);
  154.     exit (1);
  155. }
  156.  
  157. /*
  158. ** set cleanup routine for fatal() calls
  159. */
  160. fat_set (fn)
  161. int (*fn) ();
  162. {
  163.     Fatcall = fn;
  164. }
  165.  
  166. /*
  167. ** print usage message and exit.
  168. */
  169. usage (s,a,b,c,d,e,f)
  170. char *s;
  171. long a,b,c,d,e,f;
  172. {
  173.     fprintf (Diag_fp,"usage: %s ",Diag_cmd);
  174.     fprintf (Diag_fp,s,a,b,c,d,e,f);
  175.     fprintf (Diag_fp,"\n");
  176.     exit (1);
  177. }
  178. SHAR_EOF
  179. fi
  180. echo shar: "extracting 'hash.c'" '(11529 characters)'
  181. if test -f 'hash.c'
  182. then
  183.     echo shar: "will not over-write existing file 'hash.c'"
  184. else
  185. cat << \SHAR_EOF > 'hash.c'
  186. #include <stdio.h>
  187.  
  188. /*
  189. **
  190. **    Copyright (c) 1987, Robert L. McQueer
  191. **        All Rights Reserved
  192. **
  193. ** Permission granted for use, modification and redistribution of this
  194. ** software provided that no use is made for commercial gain without the
  195. ** written consent of the author, that all copyright notices remain intact,
  196. ** and that all changes are clearly documented.  No warranty of any kind
  197. ** concerning any use which may be made of this software is offered or implied.
  198. **
  199. */
  200.  
  201. /*
  202. ** generic hash table routines.
  203. **
  204. **    htab_init - initialize a new hash table
  205. **    htab_free - destroy a hash table, freeing associated memory
  206. **    htab_clear - remove all hash table entries
  207. **    htab_find - find entry
  208. **    htab_del - delete entry
  209. **    htab_enter - enter item into table
  210. **    htab_list - scan hash table entries.
  211. **
  212. ** Multiple hash tables may be used.  Caller may provide key comparison
  213. ** and hash routines, or use defaults.
  214. */
  215.  
  216. /*
  217. ** HASHMAGIC define may be used to compile a version of these routines
  218. ** which will catch bad context blocks passed in by client routines
  219. ** through a magic number check.  If defined, HASHMAGIC should be the
  220. ** actual number to use for a magic number.  Configurable so that you
  221. ** may avoid the overhead of checking it all the time in these routines
  222. ** which may have high entry rates.
  223. */
  224.  
  225. /*
  226. ** allocation: nodes are allocated starting with a block of ALLOCINIT,
  227. ** doubling the size for the next allocation as long as the size is strictly
  228. ** less than ALLOCLIMIT.  If you make ALLOCLIMIT a value encountered by
  229. ** successive doubling of ALLOCINIT, that will be the final size, otherwise the
  230. ** next doubling larger.
  231. **
  232. ** The idea of this stunt is that we don't know whether the caller is going
  233. ** to make a lot of entries, or just a few.  So we start out allocating
  234. ** just a few nodes at a crack, and as the caller makes more and more
  235. ** entries, allocate bigger bunches.  For memory-restrictive environments
  236. ** like MS-DOS, one could set ALLOCLIMIT low & simply pay the penalty for
  237. ** lots of malloc calls.
  238. */
  239. #define ALLOCINIT 25
  240. #define ALLOCLIMIT 800
  241.  
  242. #define MAGCHECK(T,N) if (T->magic != HASHMAGIC) fatal(Merr,N)
  243.  
  244. typedef struct _htab
  245. {
  246.     struct _htab *next;
  247.     char *key;
  248.     char *data;
  249. } HASHTAB;
  250.  
  251. typedef struct _faddr
  252. {
  253.     struct _faddr *next;
  254. } FADDR;
  255.  
  256. /*
  257. ** fpool, tpool - tpool is the pool of available nodes.  Every time
  258. ** a new block is allocated, one FADDR is allocated along with it.
  259. ** The address allocated is coerced into the FADDR and placed on fpool
  260. ** to facilitate freeing.
  261. */
  262.  
  263. typedef struct
  264. {
  265. #ifdef HASHMAGIC
  266.     int magic;
  267. #endif
  268.     HASHTAB **tab;        /* hash table */
  269.     HASHTAB *tpool;        /* available nodes */
  270.     HASHTAB *srch;        /* current search pointer for htab_list */
  271.     FADDR *fpool;        /* alloc pointers for htab_free */
  272.     int (*afail)();        /* allocation error handler */
  273.     int (*compare)();    /* comparison routine */
  274.     int (*hashfunc)();    /* hash function */
  275.     int size;        /* size of table (length of tab item) */
  276.     int ablock;        /* current allocation block size */
  277.     int srchidx;        /* current table index for htab_list */
  278. } CONTEXT;
  279.  
  280. extern char *malloc();
  281.  
  282. #ifdef HASHMAGIC
  283. static char *Merr = "Bad magic number in hash table context block, %s()";
  284. #endif
  285.  
  286. /*
  287. ** free hash table.  tab is pointer returned by htab_init.
  288. */
  289. htab_free(tab)
  290. char *tab;
  291. {
  292.     register FADDR *ptr, *next;
  293.     int i;
  294.     register CONTEXT *cb;
  295.  
  296.     cb = (CONTEXT *) tab;
  297.  
  298. #ifdef HASHMAGIC
  299.     MAGCHECK(cb,"htab_free");
  300.     ++(cb->magic);
  301. #endif
  302.  
  303.     for (ptr = cb->fpool; ptr != NULL; ptr = next)
  304.     {
  305.         next = ptr->next;
  306.         free ((char *) ptr);
  307.     }
  308.  
  309.     free (tab);
  310. }
  311.  
  312. /*
  313. ** remove all hash table entries.  Does not free memory, simply restores
  314. ** empty table, as if one had called htab_delete on all the keys.  tab is
  315. ** pointer returned by htab_init.
  316. */
  317. htab_clear(tab)
  318. char *tab;
  319. {
  320.     register CONTEXT *cb;
  321.     register HASHTAB **tptr;
  322.     register HASHTAB *nptr;
  323.     int i;
  324.  
  325.     cb = (CONTEXT *) tab;
  326.  
  327. #ifdef HASHMAGIC
  328.     MAGCHECK(cb,"htab_clear");
  329. #endif
  330.  
  331.     tptr = cb->tab;
  332.  
  333.     for (i=0; i < cb->size; ++i,++tptr)
  334.     {
  335.         nptr = *tptr;
  336.         if (nptr == NULL)
  337.             continue;
  338.         while (nptr->next != NULL)
  339.             nptr = nptr->next;
  340.         nptr->next = cb->tpool;
  341.         cb->tpool = *tptr;
  342.         *tptr = NULL;
  343.     }
  344.  
  345.     /* force any open htab_list's to return empty */
  346.     cb->srch = NULL;
  347.     cb->srchidx = cb->size;
  348. }
  349.  
  350. /*
  351. ** initialize a hash table.  Returns a pointer to be used with other
  352. ** calls, NULL for failure.
  353. **
  354. ** The hash table will be maintained as a linked list for each node,
  355. ** so any number of entries can be made to it, whatever the value for
  356. ** size (>100% density is perfectly OK).
  357. **
  358. **    size - size of table.  If hfunc is NULL, will be incremented
  359. **        up to a prime size to suit the type of hash function
  360. **        used by default.  Caller may find out the actual size
  361. **        by calling next_prime().
  362. **
  363. **    allocfail - routine to call in case of memory allocation failure.
  364. **        If NULL, allocation failure will make a call to fatal().
  365. **
  366. **    comp - routine used to compare keys.  returns 0 if equal, non-zero
  367. **        otherwise.  If NULL, strcmp() will be used.  Your own will
  368. **        have to be provided if your keys are something other than
  369. **        strings.  These routines will always call this with the
  370. **        comparison key as the first argument, and the one in the
  371. **        table already as a second argument.  This fact is most
  372. **        useful for making comparisons up to the length of the entered
  373. **        key, for instance.
  374. **
  375. **    hfunc - hash function.  called as (*hfunc)(key, size).  size argument
  376. **        may be ignored if function was written for a specific size.
  377. **        Must return an integer between 0 and size-1.  If NULL, the
  378. **        default hash function is the typical "string-divided-modulo
  379. **        -table-size" algorithm.
  380. */
  381. char *
  382. htab_init(size,allocfail,comp,hfunc)
  383. int size;
  384. int (*allocfail)();
  385. int (*comp)();
  386. int (*hfunc)();
  387. {
  388.     int def_afail();
  389.     int strcmp();
  390.     int hash();
  391.     int i;
  392.     CONTEXT *cb;
  393.  
  394.     if (allocfail == NULL)
  395.         allocfail = def_afail;
  396.  
  397.     if (comp == NULL)
  398.         comp = strcmp;
  399.  
  400.     if (hfunc == NULL)
  401.     {
  402.         size = next_prime(size);
  403.         hfunc = hash;
  404.     }
  405.  
  406.     i = sizeof(CONTEXT) + size * sizeof(HASHTAB *);
  407.  
  408.     if ((cb = (CONTEXT *) malloc(i)) == NULL)
  409.     {
  410.         (*allocfail)();
  411.         return (NULL);
  412.     }
  413.  
  414. #ifdef HASHMAGIC
  415.     cb->magic = HASHMAGIC;
  416. #endif
  417.  
  418.     cb->afail = allocfail;
  419.     cb->compare = comp;
  420.     cb->hashfunc = hfunc;
  421.     cb->size = size;
  422.     cb->tab = (HASHTAB **)(cb+1);
  423.  
  424.     for (i=0; i < cb->size; ++i)
  425.         (cb->tab)[i] = NULL;
  426.     cb->tpool = NULL;
  427.     cb->fpool = NULL;
  428.     cb->ablock = ALLOCINIT;
  429.  
  430.     /* safety, in case somebody calls htab_list wrong */
  431.     cb->srch = NULL;
  432.     cb->srchidx = size;
  433.  
  434.     return ((char *) cb);
  435. }
  436.  
  437.  
  438. /*
  439. ** find an entry in hash table.  The pointer returned is NULL for
  440. ** failure, or the data pointer associated with the key in htab_enter.
  441. **
  442. **    tab - table pointer returned by htab_init.
  443. **    s - search key.
  444. */
  445. char *
  446. htab_find(tab,s)
  447. char *tab;
  448. char *s;
  449. {
  450.     register HASHTAB *ptr;
  451.     register CONTEXT *cb;
  452.  
  453.     cb = (CONTEXT *) tab;
  454.  
  455. #ifdef HASHMAGIC
  456.     MAGCHECK(cb,"htab_find");
  457. #endif
  458.  
  459.     for (ptr = (cb->tab)[(*(cb->hashfunc))(s,cb->size)];
  460.                     ptr != NULL; ptr = ptr->next)
  461.     {
  462.         if ((*(cb->compare))(s,ptr->key) == 0)
  463.             return (ptr->data);
  464.     }
  465.  
  466.     return (NULL);
  467. }
  468.  
  469. /*
  470. ** delete a hash table entry.  Returns 0 for success, <0 for no entry.
  471. **
  472. **    tab - table pointer returned by htab_init.
  473. **    s - search key.
  474. */
  475. htab_del(tab,s)
  476. char *tab;
  477. char *s;
  478. {
  479.     register HASHTAB *ptr;
  480.     register CONTEXT *cb;
  481.     register HASHTAB *pred;
  482.     int idx;
  483.  
  484.     cb = (CONTEXT *) tab;
  485.  
  486. #ifdef HASHMAGIC
  487.     MAGCHECK(cb,"htab_del");
  488. #endif
  489.  
  490.     pred = NULL;
  491.     for (ptr = (cb->tab)[idx = (*(cb->hashfunc))(s,cb->size)];
  492.                         ptr != NULL; ptr = ptr->next)
  493.     {
  494.         if ((*(cb->compare))(s,ptr->key) == 0)
  495.             break;
  496.         pred = ptr;
  497.     }
  498.  
  499.     if (ptr == NULL)
  500.         return (-1);
  501.  
  502.     /*
  503.     ** if we're deleting the current search index in the middle
  504.     ** of an htab_list, go to next item.
  505.     */
  506.     if (ptr == cb->srch)
  507.         cb->srch = ptr->next;
  508.  
  509.     if (pred == NULL)
  510.         (cb->tab)[idx] = ptr->next;
  511.     else
  512.         pred->next = ptr->next;
  513.     ptr->next = cb->tpool;
  514.     cb->tpool = ptr;
  515.  
  516.     return (0);
  517. }
  518.  
  519. /*
  520. ** enter new item into hash table:
  521. **
  522. **    tab - table pointer from htab_init.
  523. **    s - key.
  524. **    data - data to associate with key.  In most cases, will probably
  525. **        actually be a pointer to some sort of structure known
  526. **        to the caller.
  527. **
  528. **    both s and data should point to storage valid for the entire life of
  529. **    the table.  htab_enter can not allocate copies of either of these
  530. **    things since it does not know their structure (if you provided 
  531. **    comparison & hash routines, the key may not actually be a string).
  532. **    htab_enter WILL allocate actual table nodes.  Returns 0 for success,
  533. **    -1 for failure.  Failure return is possible only if allocation
  534. **    failure occurs, and was not set up as fatal in htab_init().
  535. */
  536. htab_enter(tab,s,data)
  537. char *tab;
  538. char *s;
  539. char *data;
  540. {
  541.     register HASHTAB *ptr;
  542.     register CONTEXT *cb;
  543.     HASHTAB *get_node();
  544.     int i;
  545.  
  546.     cb = (CONTEXT *) tab;
  547.  
  548. #ifdef HASHMAGIC
  549.     MAGCHECK(cb,"htab_enter");
  550. #endif
  551.  
  552.     if ((ptr = get_node(cb)) == NULL)
  553.         return (-1);
  554.  
  555.     ptr->next = (cb->tab)[i = (*(cb->hashfunc))(s,cb->size)];
  556.     (cb->tab)[i] = ptr;
  557.     ptr->key = s;
  558.     ptr->data = data;
  559.     return (0);
  560. }
  561.  
  562. /*
  563. ** Routine to scan all hash table entries through successive calls.
  564. ** Returns 1 if an entry found, 0 for no more entries.  Will not
  565. ** be returned in any particular order comprehensible to the
  566. ** calling program (hash table order).
  567. **
  568. **    tab - table pointer from htab_init
  569. **    first - 1 to start scan, 0 on succesive calls.
  570. **    data, key - returned data and key.
  571. **
  572. ** Precautions have been taken to allow interleave of this routine with
  573. ** htab_del and htab_clear, but the only interleave that truly makes
  574. ** sense is to selectively htab_del() entries on some basis as they
  575. ** come back from htab_list().  htab_enter()'s in mid list scan may be
  576. ** done, but they may or may not show up on following calls, dependent
  577. ** on where they were entered in relation to the current list pointer.
  578. **
  579. ** This routine sets a global variable on all successful calls:
  580. **
  581. **    int Htab_Index; hash table index entry was found at.
  582. **
  583. ** By examining this while scanning the list of entries, a caller may
  584. ** obtain statistics on table distribution.  The value will increase
  585. ** monotonically as the search proceeds, skipping across indices
  586. ** with no entries.
  587. */
  588.  
  589. int Htab_Index;
  590.  
  591. htab_list(tab,first,data,key)
  592. char *tab;
  593. int first;
  594. char **data;
  595. char **key;
  596. {
  597.     register CONTEXT *cb;
  598.  
  599.     cb = (CONTEXT *) tab;
  600.  
  601. #ifdef HASHMAGIC
  602.     MAGCHECK(cb,"htab_list");
  603. #endif
  604.  
  605.     if (first)
  606.     {
  607.         cb->srch = NULL;
  608.         cb->srchidx = -1;
  609.     }
  610.  
  611.     while (cb->srch == NULL)
  612.     {
  613.         ++(cb->srchidx);
  614.         if (cb->srchidx >= cb->size)
  615.             return (0);
  616.         cb->srch = (cb->tab)[cb->srchidx];
  617.     }
  618.  
  619.     Htab_Index = cb->srchidx;
  620.  
  621.     *data = (cb->srch)->data;
  622.     *key = (cb->srch)->key;
  623.  
  624.     cb->srch = (cb->srch)->next;
  625.     return(1);
  626. }
  627.  
  628. static HASHTAB *
  629. get_node(cb)
  630. CONTEXT *cb;
  631. {
  632.     char *addr;
  633.     HASHTAB *ptr;
  634.     int i;
  635.  
  636.     if (cb->tpool == NULL)
  637.     {
  638.         addr = malloc((cb->ablock)*sizeof(HASHTAB)+sizeof(FADDR));
  639.         if (addr == NULL)
  640.         {
  641.             (*(cb->afail))();
  642.             return (NULL);
  643.         }
  644.  
  645.         ((FADDR *) addr)->next = cb->fpool;
  646.         cb->fpool = (FADDR *) addr;
  647.         addr += sizeof(FADDR);
  648.         cb->tpool = (HASHTAB *) addr;
  649.         for (i=1; i < cb->ablock; ++i)
  650.             (cb->tpool)[i-1].next = cb->tpool + i;
  651.         (cb->tpool)[i-1].next = NULL;
  652.  
  653.         if (cb->ablock < ALLOCLIMIT)
  654.             cb->ablock *= 2;
  655.     }
  656.  
  657.     ptr = cb->tpool;
  658.     cb->tpool = (cb->tpool)->next;
  659.     return (ptr);
  660. }
  661.  
  662. static int
  663. hash(s,size)
  664. register char *s;
  665. int size;
  666. {
  667.     register long rem;
  668.  
  669.     for (rem = 0; *s != '\0'; ++s)
  670.         rem = (rem * 128 + *s) % size;
  671.     return(rem);
  672. }
  673.  
  674. static int
  675. def_afail()
  676. {
  677.     fatal("memory allocation failure in hash table routines");
  678. }
  679. SHAR_EOF
  680. fi
  681. echo shar: "extracting 'prime.c'" '(1566 characters)'
  682. if test -f 'prime.c'
  683. then
  684.     echo shar: "will not over-write existing file 'prime.c'"
  685. else
  686. cat << \SHAR_EOF > 'prime.c'
  687. /*
  688. **
  689. **    Copyright (c) 1987, Robert L. McQueer
  690. **        All Rights Reserved
  691. **
  692. ** Permission granted for use, modification and redistribution of this
  693. ** software provided that no use is made for commercial gain without the
  694. ** written consent of the author, that all copyright notices remain intact,
  695. ** and that all changes are clearly documented.  No warranty of any kind
  696. ** concerning any use which may be made of this software is offered or implied.
  697. **
  698. */
  699.  
  700. /* return smallest prime >= i */
  701. int
  702. next_prime(i)
  703. int i;
  704. {
  705.     if (i <= 2)
  706.         return (2);
  707.     if ((i%2) == 0)
  708.         ++i;
  709.     while (! is_prime(i))
  710.         i += 2;
  711.     return (i);
  712. }
  713.  
  714. /*
  715. ** simply check all factors <= the square root of the number, with
  716. ** a minor wrinkle:
  717. **
  718. ** we split our checks into two separate chains which cover all
  719. ** numbers with no factors of 2 or 3, avoiding many of the non-
  720. ** prime factors.  factor1 winds up being all integers = 5 mod 6,
  721. ** factor2 all integers >= 7 which = 1 mod 6.  Anything = 0,2,3 or
  722. ** 4 mod 6 divides by 2 or 3.
  723. **
  724. ** this gives a rather small number of redundant factor checks for
  725. ** reasonable sized arguments (say < 10000).  Only for extremely large
  726. ** numbers would the extra overhead justify a "smarter" algorithm.
  727. **
  728. ** only valid for i >= 2.
  729. */
  730. int
  731. is_prime(i)
  732. int i;
  733. {
  734.     int factor1,factor2;
  735.  
  736.     if (i == 2 || i == 3)
  737.         return(1);
  738.  
  739.     if ((i%3) == 0 || (i%2) == 0)
  740.         return(0);
  741.  
  742.     factor1 = 5;
  743.     factor2 = 7;
  744.     while ((factor1 * factor1) <= i)
  745.     {
  746.         if ((i % factor1) == 0)
  747.             return (0);
  748.         if ((i % factor2) == 0)
  749.             return (0);
  750.         factor1 += 6;
  751.         factor2 += 6;
  752.     }
  753.  
  754.     return (1);
  755. }
  756. SHAR_EOF
  757. fi
  758. echo shar: "extracting 'strstore.c'" '(7804 characters)'
  759. if test -f 'strstore.c'
  760. then
  761.     echo shar: "will not over-write existing file 'strstore.c'"
  762. else
  763. cat << \SHAR_EOF > 'strstore.c'
  764. #include <stdio.h>
  765.  
  766. /*
  767. **
  768. **    Copyright (c) 1987, Robert L. McQueer
  769. **        All Rights Reserved
  770. **
  771. ** Permission granted for use, modification and redistribution of this
  772. ** software provided that no use is made for commercial gain without the
  773. ** written consent of the author, that all copyright notices remain intact,
  774. ** and that all changes are clearly documented.  No warranty of any kind
  775. ** concerning any use which may be made of this software is offered or implied.
  776. **
  777. */
  778.  
  779. /*
  780. ** string storage routines.
  781. **
  782. **    str_store - return an allocated copy of a string
  783. **    str_free - free all the strings
  784. **    str_cnew - make a new context block for separate group of strings
  785. **    str_ccur - return the current context block
  786. **    str_cset - set the context block
  787. **    str_cfree - free a context block
  788. **    str_afail - set allocation failure routine
  789. **
  790. ** Callers who simply need to make a single group of "permanent" strings
  791. ** for the life of their process need only call str_store, without worrying
  792. ** about context pointers.  This will probably be suitable for a lot of
  793. ** applications.  The other routines may be used to create separate groups
  794. ** of strings which may be released individually.  The burden on callers
  795. ** to keep track of current context in these cases is traded off against
  796. ** the simplicity for the other case.
  797. **
  798. ** The intent of these routines is to "micro-allocate" strings into a
  799. ** large block of storage, saving malloc() headers.  If used exclusively
  800. ** to store long strings, it might be inefficient.
  801. */
  802.  
  803. char *malloc();
  804.  
  805. /* actual malloc'ed block will be CH_BLOCK + sizeof(CHAIN) */
  806. #define CH_BLOCK (4096 - sizeof(CHAIN))
  807.  
  808. #define MAGICNUM 0x525
  809.  
  810. typedef struct _chain
  811. {
  812.     struct _chain *next;
  813.     int avail;
  814.     char *store;
  815. } CHAIN;
  816.  
  817. typedef struct
  818. {
  819.     int magic;
  820.     CHAIN *flist;
  821. } CONTEXT;
  822.  
  823. static CONTEXT Cb_def[1] =
  824. {
  825.     { MAGICNUM, NULL }
  826. };
  827.  
  828. /*
  829. ** NO_PTR_INIT may be defined if the compiler barfs on attempts
  830. ** to initialize a pointer with an array name.  If defined, extra
  831. ** checks will be made at routine entry to do the initialization
  832. ** first time through
  833. */
  834. #ifdef NO_PTR_INIT
  835. static CONTEXT *Cb = NULL;
  836. #else
  837. static CONTEXT *Cb = Cb_def;
  838. #endif
  839.  
  840. static def_afail()
  841. {
  842.     fatal ("memory allocation failure in string storage");
  843. }
  844.  
  845. static int (*Afail)() = def_afail;
  846.  
  847. /*
  848. ** str_store: return an allocated copy of a string.
  849. **
  850. **    s - the string to make a copy of.  If NULL, an empty string
  851. **        will be returned.
  852. **
  853. ** NOTE: these strings may not be individually freed.  This routine
  854. ** is intended to save memory used for alloc headers by returning
  855. ** pointers into a large blocks of allocated memory.
  856. **
  857. ** Will return NULL for allocation failure if a non-fatal failure
  858. ** routine has been defined (see str_afail).  The default failure
  859. ** routine calls "fatal" with an error message.  If the failure
  860. ** routine does not return, a NULL return from this routine is
  861. ** impossible.
  862. */
  863.  
  864. char *
  865. str_store(s)
  866. char *s;
  867. {
  868.     int len, av, idx;
  869.     char *rptr;
  870.     CHAIN *fp;
  871.  
  872. #ifdef NO_PTR_INIT
  873.     if (Cb == NULL)
  874.         Cb = Cb_def;
  875. #endif
  876.  
  877.     if (s == NULL)
  878.         s = "";
  879.  
  880.     len = strlen(s) + 1;
  881.  
  882.     /* should return inside loop */
  883.     for (idx = 0; idx < 2; ++idx)
  884.     {
  885.         for (fp = Cb->flist; fp != NULL; fp = fp->next)
  886.         {
  887.             if (fp->avail >= len)
  888.             {
  889.                 strcpy ((rptr = fp->store),s);
  890.                 fp->store += len;
  891.                 fp->avail -= len;
  892.                 return (rptr);
  893.             }
  894.         }
  895.  
  896.         /* alloc new block, let it find it on next iteration */
  897.         if (len > CH_BLOCK)
  898.             av = len;
  899.         else
  900.             av = CH_BLOCK;
  901.         if ((rptr = malloc(av + sizeof(CHAIN))) == NULL)
  902.         {
  903.             (*Afail)();
  904.             return (NULL);
  905.         }
  906.         fp = (CHAIN *) rptr;
  907.         fp->next = Cb->flist;
  908.         Cb->flist = (CHAIN *) fp;
  909.         fp->store = rptr + sizeof(CHAIN);
  910.         fp->avail = av;
  911.     }
  912.  
  913.     /* we're screwed up */
  914.     fatal("str_store: BAD craziness");
  915.     return(NULL);
  916. }
  917.  
  918. /*
  919. ** str_free:
  920. **
  921. **    Free all the strings allocated with str_store.  All of those
  922. **    pointers will no longer be valid.
  923. **
  924. **    If str_cnew / str_cset have been used, this call frees the strings
  925. **    in the current context block.
  926. **
  927. **    str_store calls may still be made after this - you're simply
  928. **    starting over.
  929. */
  930. str_free()
  931. {
  932.     CHAIN *ptr;
  933.  
  934. #ifdef NO_PTR_INIT
  935.     if (Cb == NULL)
  936.         Cb = Cb_def;
  937. #endif
  938.  
  939.     for ( ; Cb->flist != NULL; Cb->flist = ptr)
  940.     {
  941.         ptr = (Cb->flist)->next;
  942.         free ((char *) Cb->flist);
  943.     }
  944. }
  945.  
  946. /*
  947. ** str_cnew:
  948. **
  949. **    Make a new context block for str_store()
  950. **
  951. **    A pointer returned from this routine or str_ccur() is the ONLY
  952. **    valid argument for str_cset.
  953. **
  954. **    In effect what you are doing is declaring a new "pool" for all
  955. **    str_store() calls, probably so you can use str_free() to release
  956. **    groups of strings selectively.
  957. **
  958. **    NOTE: you MUST call str_cset() to actually use this new pool.
  959. **
  960. **    You MUST save this pointer to be able to add more strings to
  961. **    or free the pool.  Any number of str_cnew calls may be made,
  962. **    allowing the caller to have as many "pools" of strings as
  963. **    desired.  It is up to the caller to keep track of the context
  964. **    pointers, and which context block is currently in use.
  965. **
  966. **    NULL will be returned for failure to allocate a new context block.
  967. **    This return is only possible if a non-fatal allocation failure
  968. **    routine has been defined.
  969. */
  970. char *
  971. str_cnew()
  972. {
  973.     CONTEXT *ctx;
  974.  
  975.     /*
  976.     ** this is an inefficient use of malloc, but presumably callers
  977.     ** aren't going to define large numbers of context blocks
  978.     */
  979.     if ((ctx = (CONTEXT *) malloc(sizeof(CONTEXT))) == NULL)
  980.     {
  981.         (*Afail)();
  982.         return (NULL);
  983.     }
  984.  
  985.     ctx->magic = MAGICNUM;
  986.     ctx->flist = NULL;
  987.     return ((char *) ctx);
  988. }
  989.  
  990. /*
  991. ** str_ccur:
  992. **
  993. **    return pointer to context in current use, presumably so
  994. **    you can use str_cset to switch back to it later.
  995. */
  996. char *
  997. str_ccur()
  998. {
  999. #ifdef NO_PTR_INIT
  1000.     if (Cb == NULL)
  1001.         Cb = Cb_def;
  1002. #endif
  1003.     return ((char *) Cb);
  1004. }
  1005.  
  1006. /*
  1007. ** str_cset:
  1008. **
  1009. **    Set str_store() to a new context block. The ONLY
  1010. **    legitimate argument for this routine is an address returned
  1011. **    from a previous str_cnew() or str_ccur().
  1012. **
  1013. **    All old strings are still valid.  Only str_free returns any
  1014. **    storage.
  1015. **
  1016. **    You may recover the default context prior to any str_cset calls
  1017. **    by setting NULL
  1018. */
  1019. str_cset(ptr)
  1020. char *ptr;
  1021. {
  1022.     if (ptr == NULL)
  1023.         Cb = Cb_def;
  1024.     else
  1025.         Cb = (CONTEXT *) ptr;
  1026.     if (Cb->magic != MAGICNUM)
  1027.         fatal("bad context pointer in str_cset");
  1028. }
  1029.  
  1030. /*
  1031. ** the ONLY legal argument to this routine is pointer returned from
  1032. ** str_cnew.  This routine may be used to indicate that no more strings
  1033. ** are to be allocated on that context block, and the pointer will no
  1034. ** longer be a legal argument to str_cset.  Note that the actual
  1035. ** strings are still allocated, giving you a way to close a pool
  1036. ** while retaining the strings.  If you want to free BOTH the actual
  1037. ** string storage and the pool, you must use str_free first, then
  1038. ** switch context, so that this block is not the current context.
  1039. **
  1040. ** -1 returned for errors - attempts to free the current block or
  1041. ** the default block.
  1042. **
  1043. ** Although the current implementation makes ptr a legal address for
  1044. ** free(), callers should come through this routine instead, to
  1045. ** allow that to change.
  1046. */
  1047. str_cfree(ptr)
  1048. char *ptr;
  1049. {
  1050.     if (ptr == (char *) Cb_def || ptr == (char *) Cb)
  1051.         return (-1);
  1052.  
  1053.     if (((CONTEXT *) ptr)->magic != MAGICNUM)
  1054.         fatal("bad context pointer in str_cfree");
  1055.  
  1056.     /* make it illegal to use freed context block */
  1057.     ((CONTEXT *) ptr)->magic = MAGICNUM + 1;
  1058.  
  1059.     free(ptr);
  1060.     return(0);
  1061. }
  1062.  
  1063. /*
  1064. ** str_afail:
  1065. **
  1066. **    define the routine to be called in the event of an allocation
  1067. **    failure.  By default, fatal() will be called with an error message.
  1068. **    You may reset the default by using NULL.
  1069. **
  1070. **    Returns old failure function to allow resetting.
  1071. */
  1072.  
  1073. typedef int (*FPTR)();    /* needed typedef for Sun compiler */
  1074.  
  1075. FPTR str_afail(func)
  1076. int (*func)();
  1077. {
  1078.     int (*old)();
  1079.  
  1080.     old = Afail;
  1081.     if (func == NULL)
  1082.         Afail = def_afail;
  1083.     Afail = func;
  1084.     return (old);
  1085. }
  1086. SHAR_EOF
  1087. fi
  1088. echo shar: "extracting 'strtok.c'" '(894 characters)'
  1089. if test -f 'strtok.c'
  1090. then
  1091.     echo shar: "will not over-write existing file 'strtok.c'"
  1092. else
  1093. cat << \SHAR_EOF > 'strtok.c'
  1094. #include <stdio.h>
  1095.  
  1096. /*
  1097. ** strtok() is a routine present in SYSV and some BSD runtime libraries.
  1098. ** Use this if it isn't in yours.
  1099. */
  1100.  
  1101. static char *Save=NULL;
  1102.  
  1103. char *index ();
  1104. static char *first_ch (), *last_ch();
  1105.  
  1106. char *
  1107. strtok(str,delim)
  1108. char *str, *delim;
  1109. {
  1110.     register char *tokstart, *tokend;
  1111.  
  1112.     if (str != NULL)
  1113.         Save = str;
  1114.  
  1115.     if (Save == NULL)
  1116.         return (NULL);
  1117.  
  1118.     tokstart = first_ch (Save, delim);
  1119.     tokend = last_ch (tokstart, delim);
  1120.     Save = first_ch (tokend, delim);
  1121.     *tokend = '\0';
  1122.  
  1123.     if (*tokstart == '\0')
  1124.         return (NULL);
  1125.  
  1126.     return (tokstart);
  1127. }
  1128.  
  1129. static char *
  1130. first_ch (str,delim)
  1131. char *str;
  1132. register char *delim;
  1133. {
  1134.     register char *f;
  1135.  
  1136.     for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f)
  1137.         ;
  1138.  
  1139.     return (f);
  1140. }
  1141.  
  1142. static char *
  1143. last_ch (str,delim)
  1144. char *str;
  1145. register char *delim;
  1146. {
  1147.     register char *f;
  1148.  
  1149.     for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f)
  1150.         ;
  1151.  
  1152.     return (f);
  1153. }
  1154. SHAR_EOF
  1155. fi
  1156. exit 0
  1157. #    End of shell archive
  1158.  
  1159.